home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 July: Mac OS SDK / Dev.CD Jul 97 SDK1.toast / Development Kits (Disc 1) / QuickDraw GX / Programming Stuff / Sample Code / Typography Samples / Hebrew Layout ƒ / Hebrew Layout.c next >
Encoding:
C/C++ Source or Header  |  1996-06-18  |  17.6 KB  |  520 lines  |  [TEXT/KAHL]

  1. /**\
  2. |**| =====================================================================
  3. |**|
  4. |**|    Hebrew Layout.c
  5. |**|
  6. |**|    This file contains a sample of a layout shape using Hebrew text.
  7. |**|    It requires the Ramatgan font if you don't want to see a lot of
  8. |**|    strange characters.
  9. |**|
  10. |**|    QuickDraw GX Libraries Used:
  11. |**|    "ColorLibrary.c", "FontLibrary.c", "GraphicsDebugLibrary.c",
  12. |**|    "LayoutLibrary.c", "ShapeLibrary.c", "TransferModeLibrary.c",
  13. |**|    and "TransformLibrary.c".
  14. |**|
  15. |**|    6/96 bob    Updated #includes to support changed GX Library names.
  16. |**|                Updated the copyright date.
  17. |**|
  18. |**|    ©1990 - 1996  Apple Computer, Inc.
  19. |**|    All rights reserved.
  20. |**|
  21. |**| =====================================================================
  22. \**/
  23.  
  24.  
  25. #include "QDGX shell.h"
  26. #include <GXLayout.h>
  27. #include "LayoutLibrary.h"
  28.  
  29.  
  30. /**\
  31. |**| ---------------------------------------------------------------------
  32. |**| PROTOTYPES
  33. |**| ---------------------------------------------------------------------
  34. \**/
  35.  
  36. // funtions required by shell
  37.  
  38. void    DoSetup            (void);
  39. void    DoDraw            (WindowPtr wind, Boolean updating);
  40. OSErr    DoCreateNew        (void);
  41. void    DoDispose        (WindowPtr wind);
  42. void    DoIdle            (WindowPtr wind);
  43. void    DoTeardown        (void);
  44. void    DoClick            (WindowPtr wind, Point p);
  45.  
  46. // private functions
  47.  
  48. OSErr    DoWindowInit        (WindowPtr wind);
  49. void    CreateSampleImage    (WindowPtr wind);
  50.  
  51.  
  52. /**\
  53. |**| ---------------------------------------------------------------------
  54. |**| ENUMS
  55. |**| ---------------------------------------------------------------------
  56. \**/
  57. enum { rWindResource = 128 };
  58.  
  59.  
  60. /**\
  61. |**| ---------------------------------------------------------------------
  62. |**| GLOBALS
  63. |**| ---------------------------------------------------------------------
  64. \**/
  65. // If gDebugging = TRUE, graphics library errors and notices will be posted.  This
  66. // functionality will only work with the "debugging" version of QuickDraw GX.
  67. // If the debugging version is not installed, nothing bad will happen, but these
  68. // functions will not work. 
  69.  
  70. Boolean        gDebugging = true;
  71.  
  72. // Set  "gGiveMeValidation" to TRUE if you want receive run-time validation.
  73.  
  74. Boolean        gGiveMeValidation = true;
  75.  
  76.  
  77. // gGraphicsHeapSize sets the size of the graphics heap created by calling the
  78. // GXNewGraphicsClient routine in main () within QuickDraw GX shell.c.  You can determine
  79. // the amount of graphics heap required by using GraphicsBug.  I'm giving it 600K,
  80. // since we need abunch if we have several windows open.
  81.  
  82. long        gGraphicsHeapSize = 600;
  83.  
  84. // gOurPrintingOverrideUPP is a universal proc pointer for our printing event
  85. // override.  This is so that our override can be native PowerPC code if necessary.
  86.  
  87. GXPrintingEventUPP    gOurPrintingOverrideUPP;
  88.  
  89.  
  90.  
  91. /**\
  92. |**| ---------------------------------------------------------------------
  93. |**| DoSetup()
  94. |**| Here's where we initialize any global variables our application needs.
  95. |**| We have only one at this time -- the universal proc pointer for
  96. |**| our printing override.
  97. |**| ---------------------------------------------------------------------
  98. \**/
  99. void DoSetup (void)
  100. {    // Initialize our printing event override UPP
  101.     gOurPrintingOverrideUPP = NewGXPrintingEventProc(MyPrintingEventOverride);
  102. }
  103.  
  104.  
  105. /**\
  106. |**| ---------------------------------------------------------------------
  107. |**| DoDraw()
  108. |**| Draw the contents of the window.  The first parameter is the window
  109. |**| to draw, and the second parameter is true if we're updating an existing
  110. |**| image.  If that's the case, we don't want to change anything, but
  111. |**| just draw what's already there.
  112. |**| ---------------------------------------------------------------------
  113. \**/
  114. void DoDraw (WindowPtr wind, Boolean updating)
  115. {
  116.      #pragma unused (updating)
  117.      GXDrawShape (GetDocShape(wind));
  118. }
  119.  
  120.  
  121. /**\
  122. |**| ---------------------------------------------------------------------
  123. |**| DoCreateNew()
  124. |**| This routine is called when a window needs to be created.
  125. |**| ---------------------------------------------------------------------
  126. \**/
  127. OSErr DoCreateNew (void)
  128. {
  129.     OSErr        err = noErr;
  130.     WindowPtr    wind;
  131.     
  132. // Get and create our window from the resource fork
  133.  
  134.     wind = GetNewWindow(rWindResource, nil, (WindowPtr)-1L);
  135.  
  136. // Attach a default gxViewPort to it, create and iInitialize our
  137. // private data for it, and add a sample image to its page shape.
  138.  
  139.     if ( wind == NULL )
  140.         return (MemError());
  141.  
  142.     GXIgnoreGraphicsNotice(transform_already_set);
  143.     SetDefaultViewPort(GXNewWindowViewPort(wind));            
  144.     GXPopGraphicsNotice();
  145.     
  146.     err = DoWindowInit(wind);
  147.     if ( err != noErr )
  148.         return err;
  149.     
  150.     CreateSampleImage(wind);
  151.     return err;
  152. }
  153.  
  154.  
  155. /**\
  156. |**| ---------------------------------------------------------------------
  157. |**| DoDispose()
  158. |**| This routine is called when a window needs to be disposed of.
  159. |**| ---------------------------------------------------------------------
  160. \**/
  161. void DoDispose (WindowPtr wind)
  162. {
  163.     TH_Doc    doc;
  164.     
  165. // You should always dispose of your GX graphics objects before tossing your window.
  166. // Why?  It's generally good form and this approach guarantees that everything is
  167. // disposed.  If you had not disposed of everything, the call to DisposeWindow should
  168. // dispose of the objects. If you are running the debugging version of QuickDraw GX
  169. // with notices set, you will receive a notice that you had not disposed of everything.
  170. // You can turn notices on in this file by setting gDebugging = TRUE (above).
  171.     
  172.     if ( wind != NULL )
  173.     {
  174.         doc = (TH_Doc)GetWRefCon(wind);        // Remember, this is where we stored our private data.
  175.         GXDisposeShape(GetDocShape(wind));     // Dispose of this doc's shape.
  176.         GXDisposeJob(GetDocJob(wind));        // Dispose of this doc's print job.
  177.         DisposHandle((Handle) doc);            // Dispose of our private data.
  178.         DisposeWindow(wind);                // Dispose of the window.
  179.     }
  180. }
  181.  
  182.  
  183. /**\
  184. |**| ---------------------------------------------------------------------
  185. |**| DoIdle()
  186. |**| This routine is called to do things while idling through the event loop.
  187. |**| ---------------------------------------------------------------------
  188. \**/
  189. void DoIdle (WindowPtr wind)
  190. {
  191. }
  192.  
  193.  
  194. /**\
  195. |**| ---------------------------------------------------------------------
  196. |**| DoTeardown()
  197. |**| This routine is called just before we quit to remove anything 
  198. |**| persistent that might have been setup by DoSetup().
  199. |**| ---------------------------------------------------------------------
  200. \**/
  201. void DoTeardown (void)
  202. {
  203.     DisposeRoutineDescriptor(gOurPrintingOverrideUPP);
  204. }
  205.  
  206.  
  207. /**\
  208. |**| ---------------------------------------------------------------------
  209. |**| DoClick()
  210. |**| ---------------------------------------------------------------------
  211. \**/
  212. void DoClick(WindowPtr window, Point p)
  213. {
  214. }
  215.  
  216.  
  217.  
  218.  
  219.  
  220. /**\
  221. |**| ---------------------------------------------------------------------
  222. |**| DoWindowInit()
  223. |**| In this function we create and initialize the the private document
  224. |**| structure for a new window.  This structure contains the print job and
  225. |**| the shape which is drawn in the window.  We store this data in a handle
  226. |**| and hang it off the window's refCon field for easy retrieval.  By doing
  227. |**| this, rather than using globals, we can create many windows containing
  228. |**| unique print jobs and shapes.
  229. |**| ---------------------------------------------------------------------
  230. \**/
  231. OSErr DoWindowInit (WindowPtr wind)
  232. {
  233.     OSErr    err = noErr;
  234.     gxJob    docJob;
  235.     gxShape    docPage;
  236.     TH_Doc    windDoc;
  237.  
  238.  
  239. // Create the page shape. We set the unique items attribute to make sure that each item
  240. // added to the picture has a unique reference. If this attribute was not set, we would
  241. // not see all copies of anything we add to the shape multiple times -- we'd just see
  242. // the last version added.        
  243.  
  244.     docPage = GXNewShape(gxPictureType);
  245.     GXSetShapeAttributes(docPage, (GXGetShapeAttributes(docPage) | gxUniqueItemsShape));
  246.     
  247.     
  248. // Create a print job for this document.  This will be the same as the system default until
  249. // the user goes through the dialogs for Page Setup or Print…
  250.  
  251.     err = GXNewJob(&docJob);
  252.     
  253.     
  254. // If there are no errors, create a handle the size of our document structure and store
  255. // the print job and page shape in it.  Store the handle in the window's refCon field so
  256. // that we can get at it.  (Note that the utility routines "GetDocJob" and "GetDocShape"
  257. // can be used to do this easily.
  258.  
  259.     if ( err == noErr )
  260.     {
  261.         windDoc = (TH_Doc) NewHandleClear(sizeof(T_Doc));
  262.  
  263.         if ( windDoc == NULL )
  264.             err = MemError();
  265.         else
  266.         {
  267.             (*windDoc)->docJob = docJob;
  268.             (*windDoc)->docPage = docPage;
  269.             SetWRefCon(wind, (long) windDoc);
  270.         }
  271.  
  272. // Now install our application override for PrintingEvent so that we can
  273. // support the new movable-modal printing dialog boxes.
  274.  
  275.         GXInstallApplicationOverride(docJob, gxPrintingEventMsg, gOurPrintingOverrideUPP);
  276.  
  277.     }
  278.  
  279.     return err;
  280. }
  281.  
  282.  
  283. /**\
  284. |**| ---------------------------------------------------------------------
  285. |**| CreateSampleImage()
  286. |**| This function creates primitive shapes and adds them to the window's page shape.
  287. |**| ---------------------------------------------------------------------
  288. \**/
  289. void CreateSampleImage (WindowPtr wind)
  290. {
  291.     Rect    ourWindowRect = wind->portRect; // the rectangle for this window
  292.                                             // in QuickDraw coordinates
  293.     gxShape layout;                        // the layout shape we build
  294.     gxShape highlight;                    // the highlight shape for the layout shape
  295.     gxShape thePage;                    // this window's document shape
  296.     gxRunControls runControls;            // run controls for the layout shape
  297.     gxLayoutOptions layoutOptions;        // options for the layout shape
  298.     gxStyle timesStyle;                    // a style record for a Times-based style
  299.     gxStyle helveticaStyle;                // ditto for Helvetica
  300.     gxStyle ramatganStyle;                 // ditto for Ramat Gan
  301.     gxStyle textStyles[5];                // an array of text style for our text runs
  302.     
  303. // These are the five text runs for this layout shape, in pieces because they're
  304. // in different languages
  305.     
  306.     char *text1 = "He said “";
  307.     
  308. // The following is "Macintosh" in Hebrew: 
  309. // meem, kouf, yod,  noon, teth, vav,  shin
  310. // (This assumes the standard Hebrew character set for Macintosh, by the way)
  311.     
  312.     static char text2[] = {0xEE, 0xF7, 0xE9, 0xF0, 0xE8, 0xE5, 0xF9, 0};
  313.     
  314.     char *text3 = " (Macintosh) ";
  315.  
  316. // The following is "Hebrew" in Hebrew: 
  317. // beth, ayin, beth, rech, yoh,  tav
  318. // Same character set assumptions.
  319.     
  320.     static char text4[] =    {0xE1, 0xF2, 0xE1, 0xF8, 0xE9, 0xFA, 0};
  321.  
  322.     char *text5 =         "” to me.";
  323.  
  324.     char *textRuns[5];                    // an array of pointers to text runs
  325.  
  326.     short textLengths[5];                // an array of the lengths of each run
  327.     short totalLength;                    // the total length of the layout's text
  328.     static short levelRunLengths[3];    // an array of the lengths of each level
  329.     static short levels[3] = {0, 1, 0};    // the level numbers for each level
  330.     
  331.     gxPoint posn;                        // the position of the layout shape
  332.  
  333.  
  334. // First, initialize the textRuns array to point to the five text runs
  335.     
  336.     textRuns[0] = text1;
  337.     textRuns[1] = text2;
  338.     textRuns[2] = text3;
  339.     textRuns[3] = text4;
  340.     textRuns[4] = text5;
  341.     
  342.     
  343. // Next, initialize the textLengths and levelRunLengths arrays.  MyStrLength() is
  344. // in this file.
  345.  
  346.     textLengths[0] = MyStrLength (text1);
  347.     textLengths[1] = MyStrLength (text2);
  348.     textLengths[2] = MyStrLength (text3);
  349.     textLengths[3] = MyStrLength (text4);
  350.     textLengths[4] = MyStrLength (text5);
  351.     
  352. // Our layout has three levels in it -- level 0 for the English runs at each end,
  353. // and level 1 for the Hebrew text in the middle.  We need the byte-count for each
  354. // level's text run in the levelRunLengths array.
  355.  
  356.     levelRunLengths[0] = textLengths[0];
  357.     levelRunLengths[1] = textLengths[1] + textLengths[2] + textLengths[3];
  358.     levelRunLengths[2] = textLengths[4];
  359.  
  360.     
  361. // totalLength is the length of all the text.
  362.  
  363.     totalLength = levelRunLengths[0] + levelRunLengths[1] + levelRunLengths[2];
  364.     
  365.  
  366. // make default gxLayoutOptions and gxRunControls structures
  367.  
  368.     InitializeLayoutOptions (&layoutOptions);
  369.     InitializeRunControls (&runControls);
  370.     
  371.     
  372. // Position the layout half way down the left edge of the window. Set 
  373. // the layout's width to the window's width and set the flushness to 1/2, this
  374. // will cause the layout to center in the window.  Note that ourWindowRect is
  375. // not in fixed coordinates, so we have to make it fixed to use it.
  376.  
  377.     layoutOptions.width = ff(ourWindowRect.right - ourWindowRect.left);
  378.     layoutOptions.flush = fract1/2;
  379.  
  380.     posn.x = 0;
  381.     posn.y = ff((ourWindowRect.bottom - ourWindowRect.top) / 2);
  382.     
  383.  
  384. // Create the styles we'll use.  The helveticaStyle is 30-point Helvetica.
  385. // NewLayoutStyle is a library routine found in layout library.c.  But first,
  386. // this important message:
  387.  
  388. // When I was converting this sample to actually print, I found this strange
  389. // problem that the highlight shape, while appearing correctly on the screen,
  390. // was always too far to the right when printed -- sometimes overlapping parts
  391. // of glyphs that shouldn't be highlighted.  An investigation was launched.
  392. //
  393. // It turns out that highlight shapes are pretty much always 72 DPI, because
  394. // they're polygons calculated from the metrics of the layout shape when the
  395. // highlight shape is created.  If you then scale the layout shape by
  396. // transforming it to 300 DPI or so (like a printer driver would do), the
  397. // highlight shape has the same geometry while hinting of the glyphs may have
  398. // changed the way the layout shape looks.  They've moved a little bit, perhaps,
  399. // and therefore the highlight shape isn't in the right place anymore.
  400. //
  401. // If this is for your on-screen work, you can recreate the highlight shape in
  402. // a zoomed viewPort, but you don't get to make the printer driver do that for
  403. // you.  So, instead, for each style run we use, we add the gxNoMetricsGridText
  404. // attribute.  This prevents QuickDraw GX from using hinting, so the glyphs always
  405. // scale the same way the highlight shape does, and all is well.
  406. //
  407. // (At first, I tried to fix this by adding gxNoMetricsGridShape to the layout
  408. // _shape's_ attributes, but that's not the right idea.  The attributes in the
  409. // shape's style affect any part of the layout that doesn't have a style of its
  410. // own, including any parts of the text for which the entry in the style array
  411. // is nil.  Since we're actually applying styles over the layout here, the
  412. // gxNoMetricsGridText must be set in those styles, not in the shape's style.)
  413. //
  414. // This does mean that your glyphs won't get hinting at low resolutions and
  415. // small point sizes where it might be desirable -- but it's really only a problem
  416. // if you're trying to print a highlight shape, which doesn't happen very often.
  417. // In fact, I can't really think of a legitimate reason to want to do it, except
  418. // maybe in sample code.
  419.     
  420.     helveticaStyle = NewLayoutStyle(
  421.         (char *) "\pHelvetica",                // the gxFontName for the style
  422.         ff(30),                                // the text size in fixed point
  423.         gxNoMetricsGridText,                // gxTextAttributes
  424.         &runControls,                        // run controls (our default ones)
  425.         nil,                                // run features (none for this style)
  426.         0,                                    // count of run features
  427.         nil);                                // style run overrides (none right now)
  428.  
  429. // The second style is ramatganStyle -- Ramat Gan (Hebrew), 36 points.
  430.  
  431.     ramatganStyle = NewLayoutStyle(
  432.         (char *) "\pRamatgan",                // gxFontName
  433.         ff(36),                                // text size (fixed point)
  434.         gxNoMetricsGridText,                // gxTextAttributes
  435.         &runControls,                        // run controls (our default ones)
  436.         nil,                                 // run features (none)
  437.         0,                                     // count of run features (none)
  438.         nil);                                // style run overrides (none)
  439.     
  440. // The final style is 30-point Times Roman.
  441.  
  442.     timesStyle = NewLayoutStyle(
  443.         (char *) "\pTimes Roman",             // gxFontName
  444.         ff(30),                             // text size (fixed point)
  445.         gxNoMetricsGridText,                // gxTextAttributes
  446.         &runControls,                         // run controls (our default ones)
  447.         nil,                                 // run features (none)
  448.         0,                                     // count of run features (none)
  449.         nil);                                // style run overrides (none)
  450.     
  451.  
  452. // Initialize the textStyles array so that each of the five runs has the right style
  453.  
  454.     textStyles[0] = helveticaStyle;
  455.     textStyles[1] = ramatganStyle;
  456.     textStyles[2] = timesStyle;
  457.     textStyles[3] = ramatganStyle;
  458.     textStyles[4] = helveticaStyle;
  459.     
  460.  
  461. // Setup complete!  Build the layout.
  462.  
  463.     layout = GXNewLayout(
  464.         5,                                // count of text runs
  465.         textLengths,                    // array of lengths of each run
  466.         (void *) textRuns,                // array of pointers to the text
  467.         5,                                // count of style runs
  468.         textLengths,                    // array of the byte lengths of each run
  469.         textStyles,                        // array of the styles
  470.         3,                                // number of levels in the layout
  471.         levelRunLengths,                // array of the lengths of each level
  472.         levels,                            // array of the levels
  473.         &layoutOptions,                    // options (default)
  474.         &posn);                            // position of the layout shape
  475.  
  476.     
  477. // Retrieve the page shape so we can add to it.
  478.  
  479.     thePage = GetDocShape(wind);
  480.     
  481. // Add the layout to the window's picture shape.  AddToShape is in shape library.c.
  482.  
  483.     AddToShape(thePage, layout);
  484.  
  485. // Make a highlight shape to highlight the layout from character 5 to character 20.
  486. // This will go from the level 0 English text into the level 2 English text
  487. // which is nested in the level 1 Hebrew text, and will produce a highlight shape
  488. // consisting of three disjoint rectangles because the Hebrew text is displayed
  489. // right-to-left.  SetShapeCommonTransfer is in transferMode library.c, and
  490. // SetShapeCommonColor is in color library.c.
  491.  
  492.     highlight = GXGetLayoutHighlight(
  493.         layout,                            // the layout shape to get the highlight from
  494.         5, 20,                             // starting and ending byte offsets
  495.         gxHighlightAverageAngle,         // highlight type -- use the average angle
  496.         nil);                            // a shape to use if we have one around (we don't)
  497.     
  498.     SetShapeCommonTransfer (highlight, gxHighlightMode);
  499.     SetShapeCommonColor (highlight, gxWhite);
  500.  
  501.     
  502.     AddToShape(thePage, highlight);
  503.     
  504.  
  505. // Dispose of what we allocated
  506.  
  507.     GXDisposeShape(highlight);
  508.     GXDisposeShape(layout);
  509.     GXDisposeStyle(helveticaStyle);
  510.     GXDisposeStyle(ramatganStyle);
  511.     GXDisposeStyle(timesStyle);
  512.     
  513.  
  514. // Invalidate the window's portRect so that everything gets updated.
  515.     
  516.     SetPort(wind);
  517.     InvalRect(&ourWindowRect);
  518. }
  519.  
  520.